perm filename LINVER.SAI[SYS,HE]5 blob
sn#052048 filedate 1973-07-03 generic text, type T, neo UTF8
COMMENT ⊗ VALID 00015 PAGES
RECORD PAGE DESCRIPTION
00001 00001
00003 00002 LINVER - management of the vertex data-structure
00006 00003 _ LVOPP, NEXVER, SAMECV, SHARCV
00008 00004 _ NLINCV, RETCV, ANGDIR
00010 00005 _ LVERPT
00014 00006 _ KSCVCO
00017 00007 _ MSCVCO
00020 00008 _ MSCVCO cont.
00022 00009 _ MSCVCO cont.
00024 00010 _ MERCV
00027 00011 _ NEXLIN, RETLIN
00029 00012 _ LINDEL, LINCHA
00032 00013 _ LINSRT
00035 00014 _ LSPLIT, ANGLIN
00038 00015 _ NEXTSV, SVDIST
00040 ENDMK
⊗;
COMMENT LINVER - management of the vertex data-structure;
ENTRY LVOPP,NEXVER,SAMECV,SHARCV,NLINCV,RETCV,LVERPT,
KSCVCO,MSCVCO,MERCV,NEXLIN,RETLIN,LINDEL,LINCHA,
LINSRT,LSPLIT,LJOIN,ANGLIN,NEXTSV,SVDIST;
BEGIN "LINVER"
DEFINE QI="INTEGER",
QR="REAL",
QRI="REFERENCE INTEGER",
QRR="REFERENCE REAL",
QEP="EXTERNAL SIMPLE PROCEDURE",
QEIP="EXTERNAL SIMPLE INTEGER PROCEDURE",
QERP="EXTERNAL SIMPLE REAL PROCEDURE",
QFOP="FORWARD INTERNAL SIMPLE PROCEDURE",
QFOIP="FORWARD INTERNAL SIMPLE INTEGER PROCEDURE",
QFORP="FORWARD INTERNAL SIMPLE REAL PROCEDURE",
_="COMMENT",
LOOP(I,J,K,L)="FOR I←J STEP L UNTIL K DO",
SAFEX="SAFE";
INTEGER IA;
EXTERNAL INTEGER NOL,NOV,IFREEL,IFREEV,MAXNOL,LNCRE1,LNCRE2;
SAFEX EXTERNAL INTEGER ARRAY LEDG1,LEDG2,LCREDE,LVERSI,LVERCO,LVER,
LINK[1:1];
SAFEX EXTERNAL REAL ARRAY XVCOR,YVCOR,SVANG,XLCOR,YLCOR,RLEN,ANGARG[1:1];
QEIP ISIGN(QI I,J);
QEIP LVNEXT(QI I,J);
QEIP LCRL(QI L);
QEIP LCOMCV(QI I,J);
QEP WEIGHV(QI I; QRR R,S,T);
QERP ANGLE(QR X1,Y1,X2,Y2);
QEP MALI(QI I; QR R,S,T,U);
QEIP KARN(QR X1,Y1,X2,Y2,X3,Y3,X4,Y4; QI IC);
QEIP LACT(QI I);
QERP AMOD(QR A,B);
_ LVOPP, NEXVER, SAMECV, SHARCV;
_ Returns the s.v. opposite to the s.v. ISV (>0) on the same line.;
INTERNAL SIMPLE INTEGER PROCEDURE LVOPP(INTEGER ISV);
RETURN(4*((ISV+1)%2)-1-ISV);
_ Returns and updates pointer to free c.v. storage.;
INTERNAL SIMPLE INTEGER PROCEDURE NEXVER;
BEGIN "NEXVER"
INTEGER IDUM;
NOV←NOV+1;
IDUM←IFREEV;
IF IFREEV>0 THEN IFREEV←-1000-LVERSI[IFREEV];
RETURN(IDUM);
END "NEXVER";
_ Returns c.v. iff s.v. ISV1 and s.v. ISV2
are members of the same c.v., else 0;
INTERNAL SIMPLE INTEGER PROCEDURE SAMECV(INTEGER ISV1,ISV2);
BEGIN "SAMECV"
INTEGER IRET;
RETURN(IF(IRET←LVERCO[ABS ISV1])=LVERCO[ABS ISV2]THEN IRET ELSE 0)
END "SAMECV";
_ Returns meeting ends (0 or 1) iff lines L1 and L2
share a common vertex. Returns 0 otherwise;
INTERNAL SIMPLE INTEGER PROCEDURE SHARCV(INTEGER L1,L2);
RETURN(IF SAMECV(2*L1-1,2*L2-1) THEN 1 ELSE
IF SAMECV(2*L1-1,2*L2) THEN 3 ELSE
IF SAMECV(2*L1,2*L2-1) THEN 5 ELSE
IF SAMECV(2*L1,2*L2) THEN 7 ELSE 0);
_ NLINCV, RETCV, ANGDIR;
_ Returns number of active lines ending at ICV (if ICV>0).
If ICV<0, inactive lines are counted as well.
Temporary and permanent connections are counted alike.;
INTERNAL SIMPLE INTEGER PROCEDURE NLINCV(INTEGER ICV);
BEGIN "NLINCV"
INTEGER IDUM,IDUM1;
LABEL L1;
IDUM1←0;
IDUM←LVNEXT(ICV,1);
L1: IF IDUM=0 THEN RETURN(IDUM1);
IDUM1←IDUM1+1;
IDUM←LVNEXT(0,1);
GO L1;
END "NLINCV";
_ Returns c.v. ICV to free storage.;
INTERNAL SIMPLE PROCEDURE RETCV(INTEGER ICV);
BEGIN "RETCV"
IF LVERSI[ICV]≤-1000 THEN RETURN;
LVERSI[ICV]←-1000-IFREEV;
IFREEV←ICV;
NOV←NOV-1;
RETURN;
END "RETCV";
_ LVERPT;
_ Returns the s.v. (signed) pointing to the s.v. ISV, counting
only active lines iff ISV>0, else both kinds. Returns 0 if the
line of ISV is dead, or ISV>0 and the c.v. is inactive.;
INTERNAL SIMPLE INTEGER PROCEDURE LVERPT(INTEGER ISV);
BEGIN "LVERPT"
LABEL L1,L2;
INTEGER IV,ICV,ISV2;
IV←ABS ISV;
IF LCREDE[(IV+1)%2]≤-1000 THEN RETURN(0);
ICV←ISIGN(LVERCO[IV],ISV);
ISV2←LVNEXT(ICV,2);
GO L2;
L1: ISV2←LVNEXT(0,2);
L2: IF ISV2≠0 ∧ ABS LVER[ABS ISV2] ≠ IV THEN GO L1;
RETURN(ISV2);
END "LVERPT";
_ KSCVCO;
_ Returns 0, else number of obstructing s.v. (signed), if the
s.v. ISV may be connected to the c.v. ICV, or if ICV←0.
Counts permanent connections only, iff ISV>0, else all.
Counts only active lines iff ICV>0, else all. Uses line-
coordinates in the decision. A connection is impossible if the
line would overlap, or would shift over, any line at the c.v.
Returns LVOPP(ISV), if that end is closer than ISV to ICV.
Does not check for freedom of ISV.;
INTERNAL SIMPLE INTEGER PROCEDURE KSCVCO(INTEGER ISV,ICV);
BEGIN "KSCVCO"
LABEL L1,L2,L3;
INTEGER IDUM,ISV11,ISV12,ISV2,ICV12,ISV21,ISV22;
EXTERNAL INTEGER IP1,IP2;
ISV11←ABS ISV;
ICV12←ABS ICV;
ISV12←LVOPP(ISV11);
IF (XLCOR[ISV11]-XVCOR[ICV12])↑2+(YLCOR[ISV11]-YVCOR[ICV12])↑2>
(XLCOR[ISV12]-XVCOR[ICV12])↑2+(YLCOR[ISV12]-YVCOR[ICV12])↑2
THEN RETURN(ISV12);
IDUM←0;
IF ICV=0 THEN RETURN(IDUM);
ICV12←LVERCO[ISV12];
ISV2←LVNEXT(ICV,3);
L1: ISV21←ABS ISV2;
IF ISV21=0 THEN RETURN(IDUM);
IF ISV>0∧ISV2<0 THEN GO L2;
ISV22←LVOPP(ISV21);
IF ICV12=LVERCO[ISV22] THEN GO L3;
KARN(XLCOR[ISV11],YLCOR[ISV11],XLCOR[ISV12],YLCOR[ISV12],
XLCOR[ISV21],YLCOR[ISV21],XLCOR[ISV22],YLCOR[ISV22],0);
IF IP1=1∨IP2=1 THEN GO L2;
L3: IDUM←ISV2;
RETURN(IDUM);
L2: ISV2←LVNEXT(0,3);
GO L1;
END "KSCVCO";
_ MSCVCO;
_ Iff LADD≠0, adds the s.v. ISV at c.v. ICV (temporarily iff
ISV<0). Creates a new c.v. iff ICV=0 and ISV is free. Weighs
only active lines, iff ICV>0, else all. Line-data is assumed
existent. The program does not check that the junction is OK,
iff LADD>0, else it checks (counting all lines and connections),
and joins ISV to ICV iff everything is OK.
If LADD=2, the c.v:s are single, and the center point is used.
Iff LADD=0 ∧ ISV<0, disconnects ISV from its c.v., leaving it
loose. Iff LADD=0 ∧ ISV>0, temporizes the existing connection,
otherwise no change. May later update ANGARG for the line.
Returns 0 iff action could be completed.
Returns 10000 iff ISV is not free, and LADD≠0.
Returns number of obstructing s.v., if one exists (for LADD<0
only).;
INTERNAL SIMPLE INTEGER PROCEDURE MSCVCO(INTEGER ISV,ICV,LADD);
BEGIN "MSCVCO"
LABEL L30,L31,L310,L32,L321,L2,L20,L21,L22;
INTEGER IRET,ISV1,ICV1,ICVN,ISVN,ISVN0,ISVN0M,IDUM;
REAL ANG0,ANG1,WE;
IRET←0;
ISV1←ABS ISV;
ICV1←ABS ICV;
IF LADD=0 THEN GO L2;
IRET←10000;
IF LVERCO[ISV1]≠0 THEN RETURN(IRET);
IRET←0;
IF ICV≠0 THEN GO L30;
_ Create new c.v. for ISV.;
LVER[ISV1]←ISV;
SVANG[ISV1]←360.;
ICVN←NEXVER;
LVERSI[ICVN]←ISV1;
LVERCO[ISV1]←ICVN;
XVCOR[ICVN]←XLCOR[ISV1];
YVCOR[ICVN]←YLCOR[ISV1];
RETURN(IRET);
_ Connect ISV to ICV (check?).;
L30: IF LADD>0 THEN GO L31;
IRET←KSCVCO(-ISV1,-ICV1);
IF IRET≠0 THEN RETURN(IRET);
_ MSCVCO cont.;
_ OK, s.v. may be added to c.v.;
L31: LVERCO[ISV1]←ICV1;
ISVN←LVERSI[ICV1];
ICVN←LVERCO[LVOPP(ISVN)];
ANG1←ANGLE(XLCOR[LVOPP(ISV1)]-
(IF IDUM←(ABS LVER[ISVN]=ISVN) THEN XLCOR[ISV1] ELSE
XVCOR[ICV1]),
YLCOR[LVOPP(ISV1)]-(IF IDUM THEN YLCOR[ISV1] ELSE
YVCOR[ICV1]),
XVCOR[ICVN]-XVCOR[ICV1],YVCOR[ICVN]-YVCOR[ICV1]);
L310: ISVN0←ABS LVERPT(-ISVN);
ANG0←ANG1-SVANG[ISVN0];
IF ANG0<0. THEN GO L32;
ANG1←ANG0;
ISVN←ISVN0;
GO L310;
_ The above sequence was the loop to find the proper place for
ISV. Now that we have found it, update pointers and angles,
and weigh the compound vertex, or use center coordinates.;
L32: LVER[ISVN0]←ISIGN(ISV1,LVER[ISVN0]);
LVER[ISV1]←ISIGN(ISVN,ISV);
SVANG[ISVN0]←-ANG0;
SVANG[ISV1]←ANG1;
IF LADD≠2 THEN GO L321;
XVCOR[ICV1]←0.5*(XLCOR[ISV1]+XVCOR[ICV1]);
YVCOR[ICV1]←0.5*(YLCOR[ISV1]+YVCOR[ICV1]);
RETURN(IRET);
L321: WEIGHV(ICV1,XVCOR[ICV1],YVCOR[ICV1],WE);
RETURN(IRET);
_ Here we come to the case where ISV already belongs to a c.v.,
and we want to temporize the connection, or disconnect it.;
L2: IF ISV<0 THEN GO L20;
_ Temporize the connection.;
LVER[ISV]←-(ABS LVER[ISV]);
RETURN(IRET);
_ MSCVCO cont.;
_ Disconnect ISV from its c.v., leaving it free and loose.;
L20: ICV1←LVERCO[ISV1];
_ Change the pointer from the c.v. to its header, if necessary.;
ISVN←ABS LVER[ISV1];
IF LVERSI[ICV1] = ISV1 THEN LVERSI[ICV1]←ISVN;
IF ISVN≠ISV1 THEN GO L21;
_ The c.v. is still headed by ISV1, so ISV1 is its only s.v.,
therefore RETURN the c.v. to free storage.;
RETCV(ICV1);
GO L22;
_ Update links and angles under the c.v.;
L21: ISVN0←LVERPT(-ISV1);
ISVN0M←ABS ISVN0;
LVER[ISVN0M]←ISIGN(ISVN,ISVN0);
SVANG[ISVN0M]←SVANG[ISVN0M]+SVANG[ISV1];
IF ISVN0M=ISVN THEN
BEGIN
SVANG[ISVN]←360.;
XVCOR[ICV1]←XLCOR[ISVN];
YVCOR[ICV1]←YLCOR[ISVN]
END;
L22: LVERCO[ISV1]←0;
RETURN(IRET);
END "MSCVCO";
_ MERCV;
_ Merges the c.v. with fewest members into the other one, except
if they share a common line, or if any s.v. of one is not
attachable to the other. Treats all kinds of lines and
connections. Returns resultant c.v. (or 0, for no action).
IM ← -1 → No action if both c.v:s are simple.
IM ← 0 → Normal weight-ing procedure.
IM ← 1 → Center point is used if both c.v:s are simple.;
INTERNAL SIMPLE INTEGER PROCEDURE MERCV(INTEGER ICV1,ICV2,IM);
BEGIN "MERCV" LABEL L10,L1,L100,L101,L2,L20;
INTEGER IRET,N1,N2,ICVD,ICVN,ILOP,ISV,IDUM,I;
IF ICV1=ICV2 THEN RETURN(ICV2);
IRET←0;
IF LCOMCV(ICV1,ICV2)≠0 THEN RETURN(0);
_ Not same c.v. already, and no line in common. Proceed.;
N1←NLINCV(-ICV1);
N2←NLINCV(-ICV2);
IF IM=-1∧N1*N2=1 THEN RETURN(IRET);
ICVD ← IF N1>N2 THEN ICVD←ICV2 ELSE ICV1;
ICVN←ICV1+ICV2-ICVD;
ILOP←0;
L10: ISV←LVNEXT(-ICVD,5);
L1: IF ISV=0 THEN GO L2;
_ Iff ILOP←0, check if ISV is joinable to ICVN.
Iff ILOP←1, detach new s.v. from ICVD, and join it to ICVN.;
IF ILOP=1 THEN GO L100;
IF KSCVCO(-(ABS ISV),-ICVN)≠0 THEN RETURN(IRET) ELSE GO L101;
_ Detach the s.v. from c.v. ICVD, and attach it to ICVN.;
L100: IDUM←MSCVCO(-(ABS ISV),0,0);
I←1;
IF IM=1∧N1*N2=1 THEN I←2;
IDUM←MSCVCO(ISV,-ICVN,I);
_ Find next s.v. at ICVD, and iterate.;
L101: ISV←LVNEXT(0,5);
GO L1;
L2: IF ILOP=1 THEN GO L20;
ILOP←1;
GO L10;
L20: IRET←ICVN;
RETURN(IRET);
END "MERCV";
_ NEXLIN, RETLIN;
_ Returns and updates pointer to free line-storage.;
INTERNAL SIMPLE INTEGER PROCEDURE NEXLIN;
BEGIN "NEXLIN"
INTEGER IRET;
NOL←NOL+1;
IRET←IFREEL;
IF IFREEL>0 THEN IFREEL←-1000-LCREDE[IFREEL];
RETURN(IRET);
END "NEXLIN";
_ Returns line LL to free storage, zero-ing relevant areas.;
INTERNAL SIMPLE PROCEDURE RETLIN(INTEGER LL);
BEGIN "RETLIN"
INTEGER I1,ISV;
IF LCREDE[LL]≤-1000 THEN RETURN;
LCREDE[LL]←-1000-IFREEL;
IFREEL←LL;
NOL←NOL-1;
_ Zero line-data.;
LEDG1[LL]←0;
LEDG2[LL]←0;
_ Now zero s.v. data for the line.;
LOOP(I1,0,1,1)
BEGIN
ISV←2*LL-I1;
LVER[ISV]←0;
LVERCO[ISV]←0;
SVANG[ISV]←0.;
LINK[ISV]←0;
END ;
END "RETLIN";
_ LINDEL, LINCHA;
_ If IDAT=0 the program returns line LL to free storage.
Otherwise it changes last item on LCREDE-stack to IDAT.;
INTERNAL SIMPLE PROCEDURE LINDEL(INTEGER LL,IDAT);
BEGIN "LINDEL" INTEGER ISV,IDUM;
IF LCREDE[LL]≤-1000 THEN RETURN;
IF IDAT>0 THEN
BEGIN
LCREDE[LL]←LCREDE[LL] LAND '777777770000 LOR IDAT;
RETURN
END;
_ Line is to be deleted. First disconnect it from its c.v:s.;
IDUM←MSCVCO(1-(ISV←2*LL),0,0);
IDUM←MSCVCO(-ISV,0,0);
_ Also de-link collinear lines.;
LOOP(IA,-1,0,1) IF (ISV←LINK[2*LL+IA]) THEN LINK[ISV]←0;
_ Now (not before this point!) delete the line!;
RETLIN(LL);
END "LINDEL";
_ Always returns old LCREDE for line LL, unless LL≤0, for which
case LINCHA ← 0.
Depending on the signs of LL and NEWD the following is done:
+ ... Last on LCREDE-stack for LL is changed to IDAT
- ... Same for all lines
+ ... Deletes line LL
- ... Deletes all lines
0 + Top of LCREDE ∀ lines with LCREDE=IDAT changed to NEWD
0 0 Deletes all lines with LCREDE = IDAT;
INTERNAL SIMPLE INTEGER PROCEDURE LINCHA(INTEGER LL,IDAT,NEWD);
BEGIN "LINCHA" LABEL L1;
INTEGER IRET,I2;
IRET←0;
IF LL>0 THEN IRET←LCRL(LL);
IF LL≤0 THEN GO L1;
LINDEL(LL,IDAT);
RETURN(IRET);
L1: LOOP(I2,1,MAXNOL,1) IF LCREDE[I2]>-1000 THEN IF LL<0 THEN
LINDEL(I2,IDAT) ELSE IF LCRL(I2)=IDAT THEN LINDEL(I2,NEWD);
RETURN(IRET);
END "LINCHA";
_ LINSRT;
_ Inserts a new line between (X1,Y1) and (X2,Y2), connected to
ICV1 and ICV2, respectively, and with LCREDE ← LCRE. New c.v.
created for ICVN=0. Note that c.v. coordinates, if they exist,
do not have to agree with the given coordinates.
For X-coordinates ≤0 the c.v.-coordinates (X and Y) will be used.
The connection is made temporary for ICVN<0, else permanent.
Weighs only active lines at c.v:s. Checks that insertion is OK at
c.v:s iff ICHECK≠0.
Returns line number or the following (no-action returns):
0 iff length of line < 0.5
-1 iff line-space is exhausted
-3 iff the line could not be merged into one of the c.v:s.;
INTERNAL SIMPLE INTEGER PROCEDURE LINSRT(INTEGER ICV1,ICV2;
REAL X1,Y1,X2,Y2; INTEGER LCRE,ICHECK);
BEGIN "LINSRT" LABEL L1;
INTEGER ISV,ICV1N,ICV2N,KS1,KS2,IDUM,IRET;
REAL X,Y,R;
IF IFREEL=0 THEN RETURN(-1);
ICV1N←ABS ICV1;
ICV2N←ABS ICV2;
ISV←2*IFREEL;
IF X1≤0. THEN
BEGIN
WEIGHV(ICV1N,X,Y,R);
XVCOR[ICV1N]←X1←X; YVCOR[ICV1N]←Y1←Y
END;
IF X2≤0. THEN
BEGIN
WEIGHV(ICV2N,X,Y,R);
XVCOR[ICV2N]←X2←X;
YVCOR[ICV2N]←Y2←Y
END;
MALI(IFREEL,X1,Y1,X2,Y2);
IF RLEN[IFREEL]<0.5 THEN RETURN(0);
IF ¬ICHECK THEN GO L1;
KS1←KSCVCO(-ISV,-ICV2N);
KS2←KSCVCO(1-ISV,-ICV1N);
IF KS1+KS2≠0 THEN RETURN(-3);
_ Yes, the line may be inserted.;
L1: LCREDE[IRET←NEXLIN]←LCRE;
IDUM←MSCVCO(ISIGN(ISV-1,ICV1),ICV1N,1);
IDUM←MSCVCO(ISIGN(ISV,ICV2),ICV2N,1);
RETURN(IRET)
END "LINSRT";
_ LSPLIT, ANGLIN;
_ Replaces line LLL by two lines, one from end 1 of LLL to
(XN,YN), the other from (XN,YN) to end 2 of LLL. End links and
LCREDE remain the same. New links will be permanent.
Returns middle c.v. (or 0, if line-space is exhausted).;
INTERNAL SIMPLE INTEGER PROCEDURE LSPLIT(INTEGER LLL; REAL XN,YN);
BEGIN "LSPLIT"
INTEGER IRET,LL,ISV,ISV1,LCRE,ISVM,IDUM;
REAL XO,YO;
IRET←0;
LL←ABS LLL;
_ Check if there is space for two more lines (since the insertions
are performed prior to the deletion).;
IF IFREEL=0∨LCREDE[IFREEL]=-1000 THEN RETURN(IRET);
_ Yes, there is space for two more lines. Insert them.;
ISV←2*LL;
ISV1←ISV-1;
IRET←IFREEV;
XO←XLCOR[ISV1];
YO←YLCOR[ISV1];
LCRE←LCREDE[LL];
IDUM←LINSRT(ISIGN(LVERCO[ISV1],LVER[ISV1]),0,XO,YO,XN,YN,LCRE,0);
ISVM←2*IDUM;
LINK[ISVM]←2*IFREEL-1;
XO←XLCOR[ISV];
YO←YLCOR[ISV];
IDUM←LINSRT(IRET,ISIGN(LVERCO[ISV],LVER[ISV]),XN,YN,XO,YO,LCRE,0);
LINK[2*IDUM-1]←ISVM;
_ Now remove the old line, at last.;
LINDEL(LL,0);
RETURN(IRET);
END "LSPLIT";
_ Returns least angle between lines (directions ignored);
INTERNAL SIMPLE REAL PROCEDURE ANGLIN(INTEGER L1,L2);
RETURN(ABS(AMOD(ABS(ANGARG[L1]-ANGARG[L2])+90.,180.)-90.));
_ NEXTSV, SVDIST;
_ Returns the IND:th s.v. (signed) under the c.v. of s.v. ISV,
starting with ISV. IND>0. Returns 0 if there is no pointer,
or if there are <(IND+1) s.v:s. Counts temporary connections iff
ISV<0. Counts active lines only.;
INTERNAL SIMPLE INTEGER PROCEDURE NEXTSV(INTEGER ISV,IND);
BEGIN "NEXTSV" LABEL BA1,ON1;
INTEGER ISV1,IA,ISV2,ISV3;
IA←0;
ISV2←ABS ISV;
ISV3←ISV2;
BA1: ISV3←ABS(ISV1←LVER[ISV3]);
IF ¬ISV1 THEN RETURN(0);
IF ISV3=ISV2 THEN GO ON1;
IF ISV1<0∧ISV>0∨¬(LNCRE1≤LCREDE[(ISV3+1)%2] LAND '400000007777
≤LNCRE2) THEN GO BA1;
ON1: IF(IA←IA+1)=ABS IND THEN RETURN(ISV1) ELSE
IF ISV3=ISV2 THEN RETURN(0);
GO BA1
END "NEXTSV";
_ Returns order of ISV2 from ISV1 at common c.v. (0 if no common c.v.).
Counts active lines only. Counts permanent connections only,iff
ISV1>0;
INTERNAL SIMPLE INTEGER PROCEDURE SVDIST(INTEGER ISV1,ISV2);
BEGIN "SVDIST" INTEGER SVD,ISV;
ISV←ISV1;
SVD←0;
WHILE TRUE DO
BEGIN
ISV← ABS NEXTSV(ISIGN(ISV,ISV1),1);
SVD←SVD+1;
IF ISV=ISV2 THEN RETURN(SVD);
IF ¬ISV∨SVD>30∨ ISV = ABS ISV1 THEN RETURN(0)
END
END "SVDIST";
END "LINVER";